/**
******************************************************************************************
* @file HumidityTester.c
* @brief Management of the humidity bricklet.
* @date 29 mars 2015
* @author Benjamin Lancinot
****************************************************************************************/
/* COPYRIGHT ****************************************************************************
*****************************************************************************************
* Copyright (c) 2015, Audrey LOISEAU and Benjamin LANCINOT.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
*    list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
********************************************************************************************/

#include "HumidityTester.h"

/*******************************************************************************************
* PROTOTYPES
********************************************************************************************/

void cb_humidity(uint16_t hum, void *user_data);

void HumidityTester_initThreshold(HumidityTester *This);

void HumidityTester_destroyUtilities(HumidityTester* This);

void HumidityTester_destroy(HumidityTester** This);

int HumidityTester_registerObserver(HumidityTester* This, Observer* observer);

int HumidityTester_unregisterObserver(HumidityTester* This, Observer* observer);

/********************************************************************************************
* FUNCTIONS
********************************************************************************************/

/**
 * @brief Constructor
 * @param ipcon Ipconnection for link bricklet to the rest of bricks/bricklets
 * @return Pointer to a new HumidityTester
 **/
HumidityTester* HumidityTester_create(IPConnection ipcon){
	HumidityTester* This = (HumidityTester *) malloc(sizeof(*This));

	//Creation of humidity sensor
	Humidity humidity_sensor;
	humidity_create(&humidity_sensor, "qSp", &ipcon);
	This->humiditySensor = humidity_sensor;

	//Creation of the mercureController
        This->humidityController = HumidityController_create();
        //1 is for humidity 0 is for temperature
        This->averageMaker = AverageMaker_create(1);

        //Init functions
	This->initThreshold=HumidityTester_initThreshold;
        This->destroy = HumidityTester_destroy;
	This->subject = subjectNew(This, 2);
	This->registerObserver = HumidityTester_registerObserver;
	This->unregisterObserver = HumidityTester_unregisterObserver;

        //Init variable
        This->humidity = 0;

	return This;
}


/**
 * @brief Use by the callback function for notify observers and HumidityController and AverageMaker with the good humidity if it changed.(+ or - 1%)
 * @param hum Value of the humidity given by the bricklet
 * @param user_data Pointer to the wanted HumidityTester
 **/
void cb_humidity(uint16_t hum, void *user_data) {
	HumidityTester* This;
	This = (HumidityTester*) user_data;

        //Calculate the average of temperature
	This->averageMaker->averageMAJ(This->averageMaker,hum/10.0);

        //Notify observers when the humidity changed (+ or - 1% ).Warn HumidityController too
        if ( (((This->humidity +1) *10) < hum) || (((This->humidity  -1) *10) > hum)){
		This->humidity =  hum/10.0;
                //Give the current temperature to Mercure controller for check if it's a warning temperature
                This->humidityController->defineCriticality(This->humidityController,This->humidity);
		This->subject->notifyObservers(This->subject);
	}
}


/**
 * @brief Init the HumidityTester,the AverageMaker associate, the HumidityController associate and callback function
 * @param This Pointer to the wanted HumidityTester
 **/
void HumidityTester_initThreshold(HumidityTester *This){
        // Create the callback. It's called every second
        //humidity_set_humidity_callback_period(&This->humiditySensor, 1000);
	humidity_set_debounce_period(&This->humiditySensor, 1000);
        // Register humidity callback to function cb_humidity
	humidity_register_callback(&This->humiditySensor,
	                           HUMIDITY_CALLBACK_HUMIDITY_REACHED,
	                           (void *)cb_humidity,
	                           (void *) This);

        // Configure threshold for humidity inside 0% / 100%
	humidity_set_humidity_callback_threshold(&This->humiditySensor, 'i', 0, 100*10);


        //Recover the first humidity
        uint16_t hum;
        humidity_get_humidity(&This->humiditySensor, &hum);
        This->humidity = hum/10.0;
        This->humidityController->defineCriticality(This->humidityController,This->humidity);
        This->averageMaker->init(This->averageMaker,This->humidity);

}


/**
 * @brief Destroy all of the components of HumidityTester
 * @param This Pointer to the wanted HumidityTester
 **/
void HumidityTester_destroyUtilities(HumidityTester* This)
{
	This->subject->destroy(This->subject);
	This->humidityController->destroy(&This->humidityController);
        This->averageMaker->destroy(&This->averageMaker);
        humidity_destroy(&This->humiditySensor);
}

/**
 * @brief Destructor
 * @param This Double pointer to the wanted HumidityTester
 **/
void HumidityTester_destroy(HumidityTester** This)
{
        HumidityTester_destroyUtilities(*This);
	if (*This) {
		free(*This);
		*This = NULL;
	}
}

/**
 * @brief Proxy method for Register an observer for the HumidityTester object.
 * @param This Pointer to the wanted HumidityTester
 * @param This Pointer to the wanted observer
 * @return The result of the development of the registration (0 = GOOD and 1 = NOT GOOD)
 **/
int HumidityTester_registerObserver(HumidityTester* This, Observer* observer) {
	return This->subject->registerObserver(This->subject, observer);
}


/**
 * @brief Proxy method for Unregister observer for the HumidityTester object.
 * @param This Pointer to the wanted HumidityTester
 * @param This Pointer to the wanted observer
 * @return The result of the development of the unregistration (0 = GOOD and 1 = NOT GOOD)
 **/
int HumidityTester_unregisterObserver(HumidityTester* This, Observer* observer) {
	return This->subject->unregisterObserver(This->subject, observer);
}
